using GameToolkit.UI;
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace GameLogic.UI
{
    public class BaseToggle : Selectable, IToggle, IPointerClickHandler, ISubmitHandler, ICanvasElement, AsyncDataListView.IAsyncDataValidate
    {
        public event System.Action<IToggle> IsOnChanged;

        [SerializeField]
        bool m_ResponseSubmit = true;


        [Serializable]
        /// <summary>
        /// UnityEvent callback for when a toggle is toggled.
        /// </summary>
        public class ToggleEvent : UnityEvent<bool>
        { }

#pragma warning disable CS0649

        [SerializeField]
        private GameObject m_ToggleGroup;
        public bool IsAvailable { get { return this != null; } }
        TabToggleGroup m_Group;
        /// <summary>
        /// Group the toggle belongs to.
        /// </summary>
        public TabToggleGroup group
        {
            get { return m_Group; }
            set
            {
                if (m_Group != value)
                {
                    m_Group = value;
#if UNITY_EDITOR
                    if (Application.isPlaying && IsActive())
#else
                    if(IsActive())
#endif
                    {
                        SetToggleGroup(m_Group, true);
                    }
                }
            }
        }


        // Whether the toggle is on
        [Tooltip("Is the toggle currently on or off?")]
        [SerializeField]
        private bool m_IsOn;

        [Tooltip("当点击时仅仅选中该对象")]
        [SerializeField]
        private bool m_JustClickOn;

        [Tooltip("当高亮时自动选择")]
        [SerializeField]
        private bool m_AutoOnSelect;

        [SerializeField]
        private bool m_ClickAsButton;

        public ToggleEvent onValueChanged = new ToggleEvent();
        public UnityEvent onValueClicked = new UnityEvent();

        //SelectableNavigation mNav;
        //BaseEventData evData;
#pragma warning restore
        protected BaseToggle()
        { }

        public bool IsOn
        {
            get { return m_IsOn; }
            set
            {
                if (m_IsOn != value)
                {
                    Set(value, true);
                }
            }
        }

        protected override void DoStateTransition(SelectionState state, bool instant)
        {
            if (state != SelectionState.Highlighted && IsOn)
                state = SelectionState.Selected;
            base.DoStateTransition(state, instant);
        }

#if UNITY_EDITOR
        protected override void OnValidate()
        {
            base.OnValidate();
            if (Application.isPlaying && IsActive())
            {
                onValueChanged.Invoke(IsOn);
                IsOnChanged?.Invoke(this);
            }
            //group = m_ToggleGroup == null ? null : m_ToggleGroup.GetComponent<IToggleGroup>();
            //if (IsOn && Application.isPlaying && m_Group != null)
            //    m_Group.NotifyToggleOn(this);
            if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
                CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
        }

#endif // if UNITY_EDITOR

        public virtual void Rebuild(CanvasUpdate executing)
        {
#if UNITY_EDITOR
            if (executing == CanvasUpdate.Prelayout)
            {
                IsOnChanged?.Invoke(this);
                onValueChanged.Invoke(m_IsOn);
            }
#endif
        }

        public virtual void LayoutComplete()
        { }

        public virtual void GraphicUpdateComplete()
        { }

        protected override void Awake()
        {
            base.Awake();
            group = m_ToggleGroup == null ? null : m_ToggleGroup.GetComponent<TabToggleGroup>();
        }

        protected override void OnEnable()
        {
            base.OnEnable();
            SetToggleGroup(m_Group, true);
        }

        protected override void OnDisable()
        {
            //IsOn = false;
            var clear = group != null && group.AllowSwitchOff;
            SetToggleGroup(null, false);
            if (clear)
                IsOn = false;
            base.OnDisable();
        }

        public void ValidateAsyncData()
        {
            if (IsActive())
            {
                onValueChanged?.Invoke(this);
                if (m_Group != null && IsOn && m_Group is AsyncDataListView.IAsyncDataValidate)
                    ((AsyncDataListView.IAsyncDataValidate)m_Group).ValidateAsyncData();
            }
        }

        public override void OnSelect(BaseEventData eventData)
        {
            base.OnSelect(eventData);
            //evData = eventData;
            if (m_AutoOnSelect && eventData is AxisEventData)
            {
                IsOn = true;
                //MainThread.RunOnMainThread(AutoSelect,MainThread.ETaskType.lateTask);
            }
        }

        private void SetToggleGroup(TabToggleGroup newGroup, bool setMemberValue)
        {
            //IToggleGroup oldGroup = m_Group;

            // Sometimes IsActive returns false in OnDisable so don't check for it.
            // Rather remove the toggle too often than too little.
            if (m_Group != null)
                m_Group.UnregisterToggle(this);

            // At runtime the group variable should be set but not when calling this method from OnEnable or OnDisable.
            // That's why we use the setMemberValue parameter.
            if (setMemberValue)
                m_Group = newGroup;

            //var anyTogOn = newGroup != null && newGroup.AnyTogglesOn();
            // Only register to the new group if this Toggle is active.
            if (newGroup != null && IsActive())
                newGroup.RegisterToggle(this);

            // If we are in a new group, and this toggle is on, notify group.
            // Note: Don't refer to m_Group here as it's not guaranteed to have been set.
            //if (newGroup != null && (setMemberValue || newGroup != oldGroup))
            //{
            //    if (anyTogOn && finalToggle != this)
            //        IsOn = false;
            //    //else if (IsOn && IsActive())
            //    //    newGroup.NotifyToggleOn(this);
            //}
        }

        protected virtual void Set(bool value, bool sendCallback)
        {
            // if we are in a group and set to true, do group logic
            m_IsOn = value;
            //if (m_Group != null && IsActive())
            //{
            //    if (m_IsOn || (!m_Group.AnyTogglesOn() && !m_Group.AllowSwitchOff))
            //    {
            //        m_IsOn = true;
            //        //m_Group.NotifyToggleOn(this);
            //    }
            //}
            DoStateTransition(value ? SelectionState.Selected : (interactable ? SelectionState.Normal : SelectionState.Disabled), false);
            // Always send event when toggle is clicked, even if value didn't change
            // due to already active toggle in a toggle group being clicked.
            // Controls like Dropdown rely on this.
            // It's up to the user to ignore a selection being set to the same value it already was, if desired.
            if (sendCallback)
            {
                UISystemProfilerApi.AddMarker("Toggle.value", this);

                IsOnChanged?.Invoke(this);
                onValueChanged.Invoke(m_IsOn);
            }
        }

        protected virtual void InternalToggle(BaseEventData evData)
        {
            if (!IsActive() || !IsInteractable())
                return;
            var isOn = IsOn;
            IsOn = !isOn || m_JustClickOn;
            if ((isOn || m_ClickAsButton) && IsOn /*&& evData != this.evData*/)
            {
                onValueClicked.Invoke();
            }
        }

        /// <summary>
        /// React to clicks.
        /// </summary>
        public virtual void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
                return;
            InternalToggle(eventData);
            //this.evData = null;
        }

        public virtual void OnSubmit(BaseEventData eventData)
        {
            if (m_ResponseSubmit)
                InternalToggle(null);
        }

    }
}